import PropTypes from 'prop-types';
import React from 'react';
/**
 * 函数组件底层渲染机制
 * @1 基于babel-preset-react-app把调用的组件转换为createElement格式
 * @2 createElement方法执行，创建virtualDom对象
 * @3 基于root.render将virtualDom转为真实Dom
 *    type值不再是字符串，而是一个函数了
 *    执行函数
 *    virtualDom中的props作为实参传递给函数并执行
 *    接收函数执行的返回结果（也就是当前组件的virtualDom对象）
 *    最后基于render将组件返回的virtualDom转为真实dom，插入到#root容器中
 */

/**
 * 关于对象本身规则的设置
 * 被冻结的对象既是不可扩展的也是密封的
 * 被密封的对象也是不可扩展的
 * 
 * @1 冻结对象 =》Object.freeze(obj) 
 *  +检测是否被冻结 =》Object.isFrozen(obj)
 *  +被冻结的对象，不能新增成员 不能修改成员 不能删除现有成员 不能给成员做Object.defineProperty劫持
 * 
 * @2 密封对象 =》Object.seal(obj)
 *  +检测对象是否被密封 =》Object.isSealed(obj)
 *  +被密封的对象，不能新增成员 不能删除现有成员 不能给成员做Object.defineProperty劫持 但是可以修改现有成员
 * 
 * @3 使对象变为不可扩展 =》Object.preventExtensions(obj)
 *  +检测对象是否可扩展 =》Object.isExtensible(obj)
 *  +设置为不可扩展的对象，只是不能新增成员，可以删除现有成员，能给成员做Object.defineProperty劫持，可以修改现有成员
 */
let obj = {
  x: 10,
  y: 20,
  z: 30,
};
Object.preventExtensions(obj);
// console.log(Object.isExtensible(obj)); 
// obj.x = 100;
// obj.y = 200;
// obj.z = 300;
// obj.a = 1000;
// delete obj.z;
// Object.defineProperty(obj, 'x', {
//   get() {},
//   set() {},
// })
// console.log(obj);

/**
 * 
 * props属性 
 *  +调用组件，传递过来的props属性是只读的（只能获取，不可修改）
 *  +作用: 父组件调用子组件的时候可以通过props属性，将不同的信息传递给子组件，子组件接收相应的值呈现出不同的效果，强化组件复用性
 *  +对于传递进来的属性，我们不能直接修改，但是可以做一些规则校验
 *      设置默认值：
          FnCom.defaultProps = {
            defaultValue: 'defaultValue'
          };
 *      设置其他规则：例如数据值格式，是否必传（依赖于官方的插件）

 */

const FnCom = function FnCom (props) {
  console.log('props属性是否是被冻结的', Object.isFrozen(props));
  let { className, style, title, defaultValue, children } = props;
  title = `changed--${title}`;

  // React.Children.forEach(children, (child) => {
  //   console.log('child', child);
  // })
  children = React.Children.toArray(children);
  // 传递的插槽信息，都是编译为virtualDom后传递过来的，而不是传递的标签
  let slotHeader = children.filter((item) => item.props.slot === 'header');
  let slotFooter = children.filter((item) => item.props.slot === 'footer');
  let slotDefault = children.filter((item) => !item.props.slot);
  return (
    <div className={`function-com ${className}`} style={style}>
      {slotHeader}
      <br />

      <h2 className="title">{title}</h2>
      <h2>{defaultValue}</h2>
      {slotDefault}
      <br />

      {slotFooter}
    </div>
  )
};

//通过把函数作为对象，设置静态的私有属性方法，来给其设置属性的校验规则
FnCom.defaultProps = {
  defaultValue: 'defaultValue'
};
FnCom.propTypes = {
  title: PropTypes.string.isRequired,
  defaultValue: PropTypes.string,
  requiredX: PropTypes.number.isRequired,
  // 多种校验规则中的一个
  x: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string,
    PropTypes.bool,
  ])
};

export default FnCom;